package org.ceteca.explica.client.management;

import java.math.BigDecimal;
import java.rmi.AccessException;
import java.rmi.NotBoundException;
import java.rmi.RemoteException;
import java.rmi.registry.LocateRegistry;
import java.rmi.registry.Registry;
import java.util.ArrayList;
import java.util.HashMap;

import org.ceteca.explica.client.ClientContext;
import org.ceteca.explica.client.gui.ExplicaGUIBuilder;
import org.ceteca.explica.client.gui.common.CommonClient;
import org.ceteca.explica.core.ExplicaException;
import org.ceteca.explica.core.InterfaceErrors;
import org.ceteca.explica.core.InterfaceExplica;
import org.ceteca.explica.core.management.InterfaceManagement;
import org.ceteca.explica.core.management.InterfaceManagementErrors;
import org.ceteca.explica.core.management.ManagementManager;
import org.ceteca.explica.core.util.Converter;
import org.ceteca.explica.core.util.OperationResult;
import org.ceteca.explica.core.warehouse.LotOT;
import org.ceteca.explica.core.warehouse.ProductOT;
import org.ceteca.explica.core.warehouse.ProductStockOT;
import org.ceteca.explica.core.warehouse.WarehouseOT;
import org.ceteca.javaglade.InterfaceGladeGtk;
import org.ceteca.javaglade.JavaGladeException;
import org.ceteca.javaglade.handlers.GenericHandler;
import org.ceteca.javaglade.toolkit.swt.SwtDialog;
import org.eclipse.swt.SWT;
import org.eclipse.swt.custom.TreeEditor;
import org.eclipse.swt.events.FocusAdapter;
import org.eclipse.swt.events.FocusEvent;
import org.eclipse.swt.events.KeyAdapter;
import org.eclipse.swt.events.KeyEvent;
import org.eclipse.swt.widgets.Button;
import org.eclipse.swt.widgets.Event;
import org.eclipse.swt.widgets.Text;
import org.eclipse.swt.widgets.Tree;
import org.eclipse.swt.widgets.TreeColumn;
import org.eclipse.swt.widgets.TreeItem;

public class LotOutSelector extends GenericHandler {
	private SwtDialog dialog;

	private String guiName;

	//private ArrayList<ProductStockOT> stocks = new ArrayList<ProductStockOT>();
	private ProductOT product;
	private DocumentLineClient entLauncher;
	private WarehouseOT warehouse;
	private BigDecimal quantity;

	private static final String TOTAL_WN = "entryLotOutSelectionTotal";
	private static final String TREE_WN = "treeviewLotOutSelection";
	private static final String COD_PRODUCT_WN = "entryLotOutSelectionProductCode";
	private static final String PRODUCT_NAME_WN = "entryLotOutSelectionProductName";
	private static final String LOT_OUT_SELECTOR_DIALOG_NAME = "dialogLotOutSelection";
	private static final String LOT_OUT_SELECTOR_GLADE_PATH = "/org/ceteca/explica/client/management/explicalotoutselection.glade";
	private static final String LOT_OUT_BUTTON_OK = "buttonLotOutEntityEditionSave";
	private static final String LOT_OUT_BUTTON_CANCEL = "buttonLotOutEntityEditionCancel";
	private static final String LOT_OUT_BUTTON_UNDO = "buttonLotOutEntityEditionUndo";

	private boolean lots_selected = false;

	private Text w_quantity, w_product_code, w_product_name;
	private Tree w_tree;
	private Button w_ok, w_cancel, w_undo;

	private HashMap<ProductStockOT, BigDecimal> lotsAsignement = new HashMap<ProductStockOT, BigDecimal>();
	
	public OperationResult loadStocksFromDatabase(){
		ArrayList<ProductStockOT> stocks= new ArrayList<ProductStockOT>();
		lotsAsignement.clear();
		OperationResult result = new OperationResult();
		if (product == null)
			return result;

		try {
			ArrayList list = this.getRemoteManagement().getProductStock(
					product, warehouse);
			if (list != null) {
				stocks.addAll(list);
				for (ProductStockOT s:stocks)
					
					lotsAsignement.put(s, new BigDecimal(0));
			}
			result.setResult(OperationResult.RESULT_OK);
		} catch (ExplicaException e) {
			e.printStackTrace();
			result
					.addResultMessage(
							OperationResult.RESULT_ERROR,
							ClientContext
									.getInstance()
									.getMsgCatalog()
									.newResultMessage(
											InterfaceManagementErrors.ERR_FINDING_STOCK_AVAILABLE));
		} catch (RemoteException e) {
			e.printStackTrace();
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_RMI_NOT_BOUND));
		}
		return result;
	}
	
	
	public OperationResult updateStocksFromDatabase() {
		ArrayList<ProductStockOT> stocks= new ArrayList<ProductStockOT>();
		OperationResult result = new OperationResult();
		if (product == null)
			return result;
		try {
			ArrayList list = this.getRemoteManagement().getProductStock(
					product, warehouse);
			HashMap<ProductStockOT, BigDecimal> actual= new HashMap<ProductStockOT, BigDecimal>();
			if (list != null) {
				stocks.addAll(list);
				
				for (ProductStockOT s:stocks){
					
					boolean encontrado=false;
					for (ProductStockOT as:lotsAsignement.keySet())
						if (as.getLot().equals(s.getLot()) &&
								as.getProduct().equals(s.getProduct()) &&
								as.getWarehouse().equals(s.getWarehouse())){
									encontrado=true;
									actual.put(s, lotsAsignement.get(as));
									}
					if (!encontrado)
						actual.put(s, new BigDecimal(0));
				}
			}
			lotsAsignement.clear();
			lotsAsignement.putAll(actual);
			result.setResult(OperationResult.RESULT_OK);
		} catch (ExplicaException e) {
			e.printStackTrace();
			result
					.addResultMessage(
							OperationResult.RESULT_ERROR,
							ClientContext
									.getInstance()
									.getMsgCatalog()
									.newResultMessage(
											InterfaceManagementErrors.ERR_FINDING_STOCK_AVAILABLE));
		} catch (RemoteException e) {
			e.printStackTrace();
			result.addResultMessage(OperationResult.RESULT_ERROR, ClientContext
					.getInstance().getMsgCatalog().newResultMessage(
							InterfaceErrors.ERR_RMI_NOT_BOUND));
		}
		return result;
	}

	/**
	 * 
	 * Get access to the server via rmi
	 * 
	 * @return ManagementManager. An instance of ManagementManager used to
	 *         invoke operations on the server
	 * @throws ExplicaException
	 */
	protected ManagementManager getRemoteManagement() throws ExplicaException {

		try {

			Registry registry = LocateRegistry
					.getRegistry(InterfaceExplica.RMI_REGISTRY_PORT);

			ManagementManager manager = (ManagementManager) registry
					.lookup(InterfaceManagement.JNDI_MANAGEMENT_MANAGER_EXPORT_NAME);

			System.out.println("Management Remote Located");
			return manager;
		} catch (AccessException aEx) {
			aEx.printStackTrace();
			throw new ExplicaException(
					ClientContext
							.getInstance()
							.getMsgCatalog()
							.newResultMessage(
									InterfaceErrors.ERR_RMI_NO_ACCESS,
									aEx,
									(Object) InterfaceManagement.JNDI_MANAGEMENT_MANAGER_EXPORT_NAME,
									(Object) null));
		} catch (NotBoundException nEx) {
			nEx.printStackTrace();
			throw new ExplicaException(
					ClientContext
							.getInstance()
							.getMsgCatalog()
							.newResultMessage(
									InterfaceErrors.ERR_RMI_NOT_BOUND,
									nEx,
									(Object) InterfaceManagement.JNDI_MANAGEMENT_MANAGER_EXPORT_NAME,
									(Object) null));
		} catch (RemoteException rEx) {
			rEx.printStackTrace();
			throw new ExplicaException(
					ClientContext
							.getInstance()
							.getMsgCatalog()
							.newResultMessage(
									InterfaceErrors.ERR_RMI_METHOD_NOT_FOUND,
									rEx,
									(Object) InterfaceManagement.JNDI_MANAGEMENT_MANAGER_EXPORT_NAME,
									(Object) null));
		}
	}

	public WarehouseOT getWarehouse() {
		return warehouse;
	}

	public BigDecimal getQuantity() {
		return quantity;
	}

	public void setQuantity(BigDecimal quantity) {
		this.quantity = quantity;
	}

	public void setWarehouse(WarehouseOT warehouse) {
		this.warehouse = warehouse;
	}

	public ProductOT getProduct() {
		return product;
	}

	public void setProduct(ProductOT product) {
		this.product = product;
	}

	public LotOutSelector(DocumentLineClient entL) {
		super();
		this.entLauncher = entL;
		this.guiName = entLauncher.getEditionGui().getGuiName()
				+ "\\Explica_LotOutSelector";

	}

	public void show() {

		if (this.dialog == null) {
			this.entLauncher.getLogger().error("Error, null dialog entity");
			entLauncher.fireExceptionAndExit("Error, null dialog entity");
			return;
		}
		OperationResult result=new OperationResult();
		
		if (isLots_selected())
			result.add(updateStocksFromDatabase());
		else
			result.add(loadStocksFromDatabase());
		if (result.getResult()==OperationResult.RESULT_OK)
			result.add(loadTree());
		if (result.getResult() == OperationResult.RESULT_OK) {
			if (product != null) {
				w_product_code.setText(Converter.getInstance().toString(
						product.getIdProduct()));
				w_product_name.setText(Converter.getInstance().toString(
						product.getDescription()));
			} else {
				w_product_code.setText("");
				w_product_name.setText("");
			}
			w_quantity.setText(Converter.getInstance().toString(quantity));
			dialog.open();
		} else {
			ExplicaGUIBuilder.getInstance().showConfirmationDialog(
					this.entLauncher.getEditWindow().getShell(),
					result.getFormattedResult(), "ERROR", SWT.ICON_ERROR,
					SWT.OK);
		}

	}

	public void getWidgets() {
		ArrayList<String> codErrors = new ArrayList<String>();

		String nWidget = COD_PRODUCT_WN;
		if ((w_product_code = ((Text) this.gui.getWidget(nWidget))) == null) {
			codErrors.add(nWidget);
		}
		nWidget = PRODUCT_NAME_WN;
		if ((w_product_name = ((Text) this.gui.getWidget(nWidget))) == null) {
			codErrors.add(nWidget);
		}
		nWidget = TOTAL_WN;
		if ((w_quantity = ((Text) this.gui.getWidget(nWidget))) == null) {
			codErrors.add(nWidget);
		}

		nWidget = TREE_WN;
		if ((w_tree = ((Tree) this.gui.getWidget(nWidget))) == null) {
			codErrors.add(nWidget);
		}
		nWidget = LOT_OUT_BUTTON_OK;
		if ((w_ok = ((Button) this.gui.getWidget(nWidget))) == null) {
			codErrors.add(nWidget);
		}
		nWidget = LOT_OUT_BUTTON_CANCEL;
		if ((w_cancel = ((Button) this.gui.getWidget(nWidget))) == null) {
			codErrors.add(nWidget);
		}
		nWidget = LOT_OUT_BUTTON_UNDO;
		if ((w_undo = ((Button) this.gui.getWidget(nWidget))) == null) {
			codErrors.add(nWidget);
		}

		if (!codErrors.isEmpty()) {
			for (String error : codErrors) {
				this.entLauncher.getLogger().debug(
						"Error obteniendo widget: " + error);
				System.out.println("Error obteniendo widget: " + error);
			}
			this.entLauncher.fireExceptionAndExit("Error obteniendo widgets");
		}
	}

	public void build() {
		lots_selected = false;
		if (dialog != null) {
			this.entLauncher.getLogger().info("Error, entity already built");
			this.entLauncher
					.fireExceptionAndExit("Error, entity already built");
			return;
		}
		try {

			this.gui = ExplicaGUIBuilder.getInstance().buildGUI(guiName,
					LOT_OUT_SELECTOR_GLADE_PATH,
					this.entLauncher.getEditionGui(),
					this.entLauncher.getEditWindow());

			this.gui.printWidgets(this.entLauncher.getLogger());
			dialog = this.gui.getDialog(LOT_OUT_SELECTOR_DIALOG_NAME);

			if (dialog == null) {
				this.entLauncher.fireExceptionAndExit("Error building dialog");
			}
			getWidgets();

			if (w_tree.getColumnCount() < 1) {
				w_tree.setHeaderVisible(true);
				int columnWidth = 150;
				TreeColumn columnLot = new TreeColumn(w_tree, SWT.LEFT);
				columnLot.setText("Lot");
				columnLot.setWidth(columnWidth);
				TreeColumn columnQuantity = new TreeColumn(w_tree, SWT.RIGHT);
				columnQuantity.setText("Available");
				columnQuantity.setWidth(columnWidth);
				TreeColumn columnAsigned = new TreeColumn(w_tree, SWT.RIGHT);
				columnAsigned.setText("Asigned");
				columnAsigned.setWidth(columnWidth);
			}

/*			final TreeEditor editor = new TreeEditor(w_tree);
			editor.horizontalAlignment = SWT.LEFT;
			editor.grabHorizontal = true;
*/
/*			w_tree.addKeyListener(new KeyAdapter() {
				public void keyPressed(KeyEvent event) {
					if (event.keyCode == SWT.F2
							&& w_tree.getSelectionCount() == 1) {
						final TreeItem item = w_tree.getSelection()[0];

						final Text text = new Text(w_tree, SWT.NONE);
						text.setText(item.getText(2));
						text.selectAll();
						text.setFocus();
						text.addFocusListener(new FocusAdapter() {
							public void focusLost(FocusEvent event) {
								item.setText(2, text.getText());

								text.setVisible(false);
							}
						});
						text.addKeyListener(new KeyAdapter() {
							public void keyPressed(KeyEvent event) {
								System.out.println("Pulsada tecla "
										+ event.keyCode);
								switch (event.keyCode) {
								case SWT.CR:
									item.setText(2, text.getText());
								case SWT.ESC:
									text.setVisible(false);
									break;
								}
							}
						});
						editor.setColumn(2);
						editor.setEditor(text, item);
					}
				}
			});
*/
			
			// Add the lot out editor
			LotOutListener listener = new LotOutListener(this.gui, this.w_tree);
			this.w_tree.addListener(SWT.KeyDown, listener);
			
			ExplicaGUIBuilder.getInstance().connectSignal(
					InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, w_ok,
					"on_ok_button_clicked", this);
			ExplicaGUIBuilder.getInstance().connectSignal(
					InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, w_undo,
					"on_undo_button_clicked", this);
			ExplicaGUIBuilder.getInstance().connectSignal(
					InterfaceGladeGtk.GTK_SIGNAL_TYPE_CLICKED, w_cancel,
					"on_cancel_button_clicked", this);

		} catch (JavaGladeException e) {
			entLauncher.getLogger()
					.error("Error building Lot Selection Dialog");
			e.printStackTrace();
			this.entLauncher
					.fireExceptionAndExit("Error building Lot Selection Dialog");

		}

	}

	public OperationResult validate() {
		OperationResult result = new OperationResult();
		boolean datosvalidos = true;
		for (TreeItem t : w_tree.getItems()) {

			BigDecimal st = Converter.getInstance().parseBigDecimal(
					t.getText(1));
			BigDecimal as = Converter.getInstance().parseBigDecimal(
					t.getText(2));
			if (st.compareTo(as) < 0)
				datosvalidos = false;

		}

		if (!datosvalidos)
			result
					.addResultMessage(
							OperationResult.RESULT_ERROR,
							ClientContext
									.getInstance()
									.getMsgCatalog()
									.newResultMessage(
											InterfaceManagementErrors.MSG_LOT_STOCK_VALIDATE_ERROR));

		else
			result
					.addResultMessage(
							OperationResult.RESULT_OK,
							ClientContext
									.getInstance()
									.getMsgCatalog()
									.newResultMessage(
											InterfaceManagementErrors.MSG_LOT_STOCK_VALIDATE_OK));

		return result;
	}

	public void on_ok_button_clicked(Event e) {

		// AQUI leer los valores del arbol y almacenarlos en el HahsMap
		saveTree();
		
		
		
		lots_selected = true;
		entLauncher.generateMovements(this.lotsAsignement);
		
		dialog.close();
		
	}

	public void on_undo_button_clicked(Event e) {

		loadTree();
	}

	public void on_cancel_button_clicked(Event e) {
		// lots_selected=false;
		dialog.close();
	}

	public boolean isLots_selected() {
		return lots_selected;
	}

	public void setLots_selected(boolean lotsSelected) {
		lots_selected = lotsSelected;
	}

	public HashMap<ProductStockOT, BigDecimal> getLotsAsignement() {
		return lotsAsignement;
	}

	public void setLotsAsignement(HashMap<ProductStockOT, BigDecimal> lotsAsignement) {
		this.lotsAsignement = lotsAsignement;
	}

	
	
	
	private void saveTree() {




			HashMap<ProductStockOT, BigDecimal> actual= new HashMap<ProductStockOT, BigDecimal>();
			
			for (TreeItem t:w_tree.getItems()){
				String lote=t.getText(0);
				BigDecimal q=Converter.getInstance().parseBigDecimal(t.getText(2));
				for (ProductStockOT s:lotsAsignement.keySet()){
					if (s.getLotNumber().equals(lote)){
						actual.put(s, q);
					}
						
				}
			}
			lotsAsignement.clear();
			lotsAsignement.putAll(actual);
			System.out.println("Guardando "+actual.size()+" entradas");
			
		

	}
	
	

	
	
	
	private OperationResult loadTree() {

		OperationResult result = loadStocksFromDatabase();

		if (result.getResult() == OperationResult.RESULT_OK) {

			w_tree.clearAll(true);
			w_tree.removeAll();
			for (ProductStockOT s : lotsAsignement.keySet()) {

				TreeItem item = new TreeItem(w_tree, SWT.NONE);
				String[] it = new String[3];
				it[0] = s.getLotNumber();
				it[1] = Converter.getInstance().toString(s.getStock());
				it[2] = Converter.getInstance().toString(lotsAsignement.get(s));
				item.setText(it);
			}
		}
		return result;

	}

}
